// AlarmServerExample.cpp
//
// Copyright (c) 2006 Symbian Software Ltd.  All rights reserved.

// System includes
#include <e32base.h>
#include <e32cons.h>
#include <asshdalarm.h>
#include <asclisession.h>

// Local includes
#include "AlarmServerExample.h"

// Global definition
static CConsoleBase* gConsole;
// Strings for display
_LIT(KConsoleStars,"\n*************************");

CExampleAlarmServer* CExampleAlarmServer::NewL()
	{
	CExampleAlarmServer* self = new (ELeave) CExampleAlarmServer();
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}
	
void CExampleAlarmServer::ConstructL()
	{
	// connect to the alarm server
	User::LeaveIfError(iAlarmServerSession.Connect());
	}	
	
CExampleAlarmServer::~CExampleAlarmServer()	
	{
	iAlarmServerSession.Close();
	}

// Called each time the alarm server generates an event. Displays a description of the event.
void CExampleAlarmServer::DisplayNotificationType(TAlarmChangeEvent aAlarmChangeEvent, TAlarmId /*aAlarmId*/)
	{
	switch (aAlarmChangeEvent)
		{
		case EAlarmChangeEventUndefined:
			_LIT(KConsoleMsg, "\nAn undefined alarm event has occurred.");
			gConsole->Printf(KConsoleMsg);
			break;
		case EAlarmChangeEventState:
			_LIT(KConsoleMsg1, "\nAn alarm has changed state.");
			gConsole->Printf(KConsoleMsg1);
			break;
		case EAlarmChangeEventStatus:
			_LIT(KConsoleMsg2, "\nAn alarm has changed status.");
			gConsole->Printf(KConsoleMsg2);
			break;
		case EAlarmChangeEventCharacteristics:
			_LIT(KConsoleMsg3, "\nAn alarm has changed characteristics..");
			gConsole->Printf(KConsoleMsg3);
			break;
		case EAlarmChangeEventAlarmDeletion:
			_LIT(KConsoleMsg4, "\nAn alarm has been deleted from the queue.");
			gConsole->Printf(KConsoleMsg4);
			break;
		case EAlarmChangeEventAlarmAddition:
			_LIT(KConsoleMsg5, "\nAn alarm has been added to the queue.");
			gConsole->Printf(KConsoleMsg5);
			break;
		case EAlarmChangeEventTimerExpired:
			_LIT(KConsoleMsg6, "\nAn alarm has expired.");
			gConsole->Printf(KConsoleMsg6);
			break;
		case EAlarmChangeEventSoundPlaying:
			_LIT(KConsoleMsg7, "\nThe sound for an alarm has just started playing.");
			gConsole->Printf(KConsoleMsg7);
			break;
		case EAlarmChangeEventSoundStopped:
			_LIT(KConsoleMsg8, "\nThe sound for an alarm has just stopped playing.");
			gConsole->Printf(KConsoleMsg8);
			break;
		case EAlarmChangeEventPlayIntervalsChanged:
			_LIT(KConsoleMsg9, "\nThe sound intervals associated with sound timing have changed.");
			gConsole->Printf(KConsoleMsg9);
			break;
		case EAlarmChangeEventGlobalSoundStateChanged:
			_LIT(KConsoleMsg10, "\nThe global sound state (on/off) has changed.");
			gConsole->Printf(KConsoleMsg10);
			break;
		case EAlarmChangeEventHeadQueueItemChanged:
			_LIT(KConsoleMsg11, "\nThe next alarm at the head of the alarm queue has changed.");
			gConsole->Printf(KConsoleMsg11);
			break;
		case EAlarmChangeEventSystemDateTimeChanged:
			_LIT(KConsoleMsg12, "\nThe system date or time has changed, or the days defined as workdays have changed.");
			gConsole->Printf(KConsoleMsg12);
			break;
		case EAlarmChangeEventAlarmUIVisible:
			_LIT(KConsoleMsg13, "\nThe alarm alert server has been instructed to show the 'alarm expired' display.");
			gConsole->Printf(KConsoleMsg13);
			break;
		case EAlarmChangeEventAlarmUIInvisible:
			_LIT(KConsoleMsg14, "\nThe alarm alert server has been instructed to hide the 'alarm expired' display.");
			gConsole->Printf(KConsoleMsg14);
			break;
		case EAlarmChangeEventSoundSilence:
			_LIT(KConsoleMsg15, "\nAlarm sounds have been temporarily silenced, the current alarm has been paused or re-enabled.");
			gConsole->Printf(KConsoleMsg15);
			break;
		case EAlarmChangeEventAlarmData:
			_LIT(KConsoleMsg16, "\nThe data associated with an alarm has changed.");
			gConsole->Printf(KConsoleMsg16);
			break;
		case EAlarmChangeEventRestoreStarted:
			_LIT(KConsoleMsg17, "\nA restore from backup of the alarm server has started. Alarms cannot be added/deleted until this has finished.");
			gConsole->Printf(KConsoleMsg17);
			break;
		case EAlarmChangeEventRestoreFailed:
			_LIT(KConsoleMsg18, "\nA restore from backup of the alarm server has failed. Alarms can be added/deleted again.");
			gConsole->Printf(KConsoleMsg18);
			break;
		case EAlarmChangeEventRestoreCompleted:
			_LIT(KConsoleMsg19, "\nA restore from backup of the alarm server has completed. The alarm queue has changed.");
			gConsole->Printf(KConsoleMsg19);
			break;
		case EAlarmChangeEventLast:
			_LIT(KConsoleMsg20, "\nLast change event (anchor). This is always at the end of the list.");
			gConsole->Printf(KConsoleMsg20);
			break;
		}
	}
	

// Waits for the alarm to be cleared by the user.
// In the meantime, prints out descriptions of all change events generated by server.
void CExampleAlarmServer::WaitForAlarmToBeCleared()
	{
	TAlarmChangeEvent alarmChangeEvent;
	do
		{
		TRequestStatus status;	
		TAlarmId alarmId;
		iAlarmServerSession.NotifyChange(status, alarmId);
		User::WaitForRequest(status);
		alarmChangeEvent = static_cast<TAlarmChangeEvent>(status.Int());
		DisplayNotificationType(alarmChangeEvent,alarmId);
		}
	// EAlarmChangeEventAlarmUIInvisible is generated when the alarm is cleared
	while (alarmChangeEvent != EAlarmChangeEventAlarmUIInvisible);
	}
	
// Sets a floating alarm and adds it to the alarmserver queue.
// This is an alarm that is set using local time, for example a morning wake up call.
void CExampleAlarmServer::SetFloatingAlarmL()
	{
	/*
	There are two types of alarms - floating and fixed.
	For a floating alarm, time is set in local time by using TASShdAlarm::NextDueTime().
	A floating alarm will be rescheduled when the UTC offset is changed.

	In case of fixed alarms, time is set in UTC by using TASShdAlarm::SetUtcNextDueTime().
	A fixed alarm will not be rescheduled when the UTC offset is changed.
	*/
	_LIT(KConsoleMsg, "\nPress any key to add a floating alarm");
	gConsole->Printf(KConsoleMsg);
	_LIT(KConsoleMsg2,"\nWhen notification occurs, press Clear to continue");
	gConsole->Printf(KConsoleMsg2);
	gConsole->Getch();
	gConsole->Printf(KConsoleStars);

	TASShdAlarm alarm;
	alarm.Category() = KASCliCategoryClock;
	// Alarm occurs once, today. This is the default.
	alarm.RepeatDefinition() = EAlarmRepeatDefintionRepeatOnce;
	_LIT(KAlarmMessage,"\nThis is a floating alarm.");
	alarm.Message() = KAlarmMessage;
	// Get the local time and set it as the alarm's due time
	alarm.NextDueTime().HomeTime();
	// Set alarm to expire in the past - should go off immediately.
	// Note that if the alarm was of type EAlarmRepeatDefintionRepeatNext24Hours
	// it would expire tomorrow.
	alarm.NextDueTime() -= TTimeIntervalSeconds(2); 
	
  	// WriteUserData capability is required to add an alarm
  	User::LeaveIfError(iAlarmServerSession.AlarmAdd(alarm));
	// Wait for the user to clear the alarm
	WaitForAlarmToBeCleared();
	}

// Displays the state of the alarm
void CExampleAlarmServer::DisplayAlarmState(TAlarmState aState)
	{
	switch (aState)
		{
		case EAlarmStateInPreparation:
			_LIT(KConsoleMsg1, "\nThe alarm state is not currently known by the alarm server..");
			gConsole->Printf(KConsoleMsg1);
			break;
		case EAlarmStateQueued:
			_LIT(KConsoleMsg2, "\nThe alarm is in the queue.");
			gConsole->Printf(KConsoleMsg2);
			break;
		case EAlarmStateSnoozed:
			_LIT(KConsoleMsg3, "\nThe alarm is snoozed. When the snooze period is over, the alarm expires again.");
			gConsole->Printf(KConsoleMsg3);
			break;
		case EAlarmStateWaitingToNotify:
			_LIT(KConsoleMsg4, "\nThe alarm is waiting to be notified.");
			gConsole->Printf(KConsoleMsg4);
			break;
		case EAlarmStateNotifying:
			_LIT(KConsoleMsg5, "\nThe alarm is currently notifying"); 
			gConsole->Printf(KConsoleMsg5);
			break;
		case EAlarmStateNotified:
			_LIT(KConsoleMsg6, "\nThe alarm has already notified and has been dismissed.");
			gConsole->Printf(KConsoleMsg6);
			break;
		}
	}
	

// Sets a fixed alarm and adds it to the alarmserver's queue.
// This is an alarm that is set using UTC, so will not change if 
// for instance the system time zone changes.
// This function fetches and prints alarm details.
void CExampleAlarmServer::AddFetchDeleteFixedAlarmL()
	{
	gConsole->Printf(KConsoleStars);
	_LIT(KConsoleMsg, "\nPress any key to add a fixed alarm");
	gConsole->Printf(KConsoleMsg);
	gConsole->Getch();

	TASShdAlarm alarm;
	TAlarmCategory alarmCategory = KASCliCategoryClock;
	alarm.Category()=alarmCategory;
	_LIT(KAlarmMessage, "This is a fixed alarm");
	alarm.Message() = KAlarmMessage;
	_LIT(KAlarmSound, "Chimes");
	alarm.SoundName() = KAlarmSound;
    // Alarm occurs once. 
    alarm.RepeatDefinition() = EAlarmRepeatDefintionRepeatOnce;
    
	TTime time;
	// Time is set in UTC for a fixed alarm 
	time.UniversalTime();
	// Set alarm to expire in 2 seconds. 
	time += TTimeIntervalSeconds(2);
	alarm.SetUtcNextDueTime(time);
	
  	// WriteUserData capability is required to add an alarm
	User::LeaveIfError(iAlarmServerSession.AlarmAdd(alarm));
  
	// Fetch some details about the alarm from the server and print them
	const TAlarmId id = alarm.Id();
	TAlarmCategory category;
	User::LeaveIfError(iAlarmServerSession.GetAlarmCategory(id, category));
	User::LeaveIfError(iAlarmServerSession.GetAlarmDetails(id, alarm));

	TAlarmState state = alarm.State();
	DisplayAlarmState(state);
	
	TAlarmMessage message = alarm.Message();
	TBuf<256> messageBuf;
	messageBuf.Copy(message);
	_LIT(KConsoleMessage,"\nThe alarm's message is....:");
	gConsole->Printf(KConsoleMessage);
	gConsole->Printf(messageBuf);
	
	TAlarmSoundName soundName = alarm.SoundName();
	messageBuf.Copy(soundName);
	_LIT(KConsoleSoundName,"\nThe alarm's sound name is ....:");
	gConsole->Printf(KConsoleSoundName);
	gConsole->Printf(messageBuf);
		
	_LIT(KDeleteMsg, "\n\nPress any key to finish");
	gConsole->Printf(KDeleteMsg);
	gConsole->Getch();

	User::LeaveIfError(iAlarmServerSession.AlarmDelete(id));
	}
	

void CExampleAlarmServer::EgAlarmServerL()
	{
	SetFloatingAlarmL();
	AddFetchDeleteFixedAlarmL();
	}

static void DoExampleL()
	{
	// Create the console to print the messages to.
	_LIT(KConsoleMessageDisplay, "Alarm Server Example");
	gConsole = Console::NewL(KConsoleMessageDisplay,TSize(KConsFullScreen,KConsFullScreen));
	CleanupStack::PushL(gConsole);
	gConsole->Printf(KConsoleMessageDisplay);
	gConsole->Printf(KConsoleStars);

	CExampleAlarmServer* egAlarmServer= CExampleAlarmServer::NewL();
	TRAPD(err, egAlarmServer->EgAlarmServerL());
	if (err)
		{
		_LIT(KFailed,"\n\nExample failed: leave code=%d");
		gConsole->Printf(KFailed, err);
		gConsole->Getch();
		}
	delete egAlarmServer;	
	CleanupStack::PopAndDestroy(gConsole);
	}

// Standard entry point function
TInt E32Main()
	{
	__UHEAP_MARK;
	// Active scheduler required as this is a console app
	CActiveScheduler* scheduler=new CActiveScheduler;
	// If active scheduler has been created, install it.
	if (scheduler)
		{
		CActiveScheduler::Install(scheduler);
		// Cleanup stack needed
		CTrapCleanup* cleanup=CTrapCleanup::New();
		if (cleanup)
			{
			TRAP_IGNORE(DoExampleL());
			delete cleanup;
			}
		delete scheduler;
		} 
	__UHEAP_MARKEND;
	return KErrNone;
	}
